﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using System.Web.Http.Routing;
using System.Web.Http.Validation;

using Newtonsoft.Json;

using ProjectBase.Core;

using $prjsn$.Tools.RestApi;

namespace $safeprojectname$
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Services.Replace(typeof(IHttpControllerSelector), new ServiceSelector(config));

            config.Services.Replace(typeof(IHttpControllerActivator), new ServiceActivator(config));

            SetFormatters(config);

            // the url mapping
            SetRouting(config);

            // the special binder for Filter
            SetBinding(config);

            // remove crazy validators built in api
            SetValidators(config);

            config.MessageHandlers.Add(new CrossDomainDelegationHandler());
        }
        #region validators

        static void SetValidators(HttpConfiguration config)
        {
            // the reflection over existing entities creates endless chain calls...
            // built in Validators cannot be used

            var validators = config.Services.GetModelValidatorProviders().ToList();
            foreach (var validator in validators)
            {
                config.Services.Remove(typeof(ModelValidatorProvider), validator);
            }
        }
        #endregion validators

        #region formatters
        static void SetFormatters(HttpConfiguration config)
        {
            // xml not supported
            var xmlFormatter = config.Formatters.XmlFormatter;
            config.Formatters.Remove(xmlFormatter);

            // built in json will be replaced per request
            var json = config.Formatters.First() as System.Net.Http.Formatting.JsonMediaTypeFormatter;
            config.Formatters.Remove(json);

        }
        #endregion formatters

        #region binding

        static void SetBinding(HttpConfiguration config)
        {
            var rules = config.ParameterBindingRules;
            rules.Insert(0, ModelBinderSelector);
        }

        static HttpParameterBinding ModelBinderSelector(HttpParameterDescriptor parameter)
        {
            if (parameter.ParameterType.HasType(typeof(IFilter<int>)))
            {
                return parameter.BindWithModelBinding(new FilterModelBinder());
            }
            return null;
        }
        #endregion binding

        #region routing

        static void SetRouting(HttpConfiguration config)
        {
            SetGetMethod(config);

            config.Routes.MapHttpRoute(
                name: "SpecialAction",
                routeTemplate: "api/{controller}/Action/{actionName}/{id}",
                defaults: new { action = "SpecialAction" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Put) }
                );

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

        static void SetGetMethod(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "Find",
                routeTemplate: "api/{controller}/Find",
                defaults: new { action = "Find" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "Token",
                routeTemplate: "api/{controller}/Token",
                defaults: new { action = "Token" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "MetaData",
                routeTemplate: "api/{controller}/MetaData",
                defaults: new { action = "MetaData" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "New",
                routeTemplate: "api/{controller}/New",
                defaults: new { action = "New" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "Query",
                routeTemplate: "api/{controller}/",
                defaults: new { action = "Query" }
                , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "GetApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { action = "GetById", id = RouteParameter.Optional }
                , constraints: new { id = @"\d+", httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
            config.Routes.MapHttpRoute(
                name: "ActionApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { action = "GetById", id = RouteParameter.Optional }
                , constraints: new { id = @"\d+", httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
                );
        }
        #endregion routing
    }
}
